//********************************************************
// PopupMenu.java 
// Date: 4/4/2012
// Author: Jeff Xiong
//********************************************************
// Popup menu which displays the current contents of the players hand.
// Upon selecting a choice it uses Tile.java to place the proper image on the 
// board at the specified board location.
// ******************************************************
// Edit: Andrew Landphier - Added knight removal, player numbering

package functionality;

import java.awt.Color; 
import java.io.Serializable;
import java.util.ArrayList;

import javax.swing.ImageIcon;

import driver.Driver;

import ui.Tile;

public class Player implements Serializable{
	private ArrayList<Knight> knights=new ArrayList<Knight>();
	
	private ArrayList<Tile> tileA = new ArrayList<Tile>();
	private ArrayList<Tile> tileB = new ArrayList<Tile>();
	private ArrayList<Tile> tileC = new ArrayList<Tile>();
	private ArrayList<Tile> tileD = new ArrayList<Tile>();
	private ArrayList<Tile> tileE = new ArrayList<Tile>();
	
	private ArrayList<Tile> _playerHand = new ArrayList<Tile>();
	
	
	private ImageIcon icon;
	private int numPlayer;
	private Color _color;
	private int _numCards=0;
	//private int _numKnights;
	
	/**
	 * constructor to create list of knights and Tile.
	 * involves creating Tile with the land and building, 
	 * and drawing first castle card and second card of choice
	 * 
	 * @param Color c for color of player
	 * @param String land
	 * @param String building
	 * @param int numPlayer for the current player number
	 * @return Player object	 
	 */
	// TODO remove debug statements
	public Player(Color c, String land,String building, int numPlayer)
	{
		this.numPlayer = numPlayer;
		
		//Set the icon associated with the player
		matchAndSetIcon(c);
		
		_color=c;
		for(int i=0;i<30;++i)
		{
			knights.add(new Knight(c));
			//++_numKnights;
		}
			
		//Create tile A and shuffle deck
		tileA.add(new Tile("plain",1,"castle",1 ));
		//tileA.add(new Tile("lake",-1,"none",0 ));
		tileA.add(new Tile("mountain",3,"none",0 ));			
		tileA.add(new Tile("plain",1,"village",2 ));
		tileA.add(new Tile("plain",1,"none",0 ));
		_numCards=4;
		
		shuffle(tileA);
		//System.out.println(tileA.size()+"SIZZZZZZZZZZZZZZEEEEEEEEE aaaaaaa");
			
		//Create tile b and shuffle deck
		tileB.add(new Tile("plain",1,"castle",1 ));
		tileB.add(new Tile("plain",1,"town",3 ));
		tileB.add(new Tile("plain",1,"village",2 ));
		tileB.add(new Tile("forest",2,"village",2 ));
		tileB.add(new Tile("lake",-1,"none",0 ));
			
		shuffle(tileB);
		//System.out.println(tileB.size()+"SIZZZZZZZZZZZZZZEEEEEEEEE bbbbbbb");
		_numCards+=5;
		
		//Create tile c and shuffle deck
		tileC.add(new Tile("plain",1,"none",0 ));
		tileC.add(new Tile("plain",1,"castle",1 ));			
		tileC.add(new Tile("plain",1,"village",2 ));
		tileC.add(new Tile("forest",2,"castle",1 ));
		tileC.add(new Tile("forest",2,"town",3 ));	
		
		shuffle(tileC);
		//System.out.println(tileC.size()+"SIZZZZZZZZZZZZZZEEEEEEEEE cccccccc");
		_numCards+=5;
			
		//Create tile d and shuffle deck
		tileD.add(new Tile("mountain",3,"none",0 ));	
		tileD.add(new Tile("plain",1,"castle",1 ));
		tileD.add(new Tile("plain",1,"castle",1 ));
		tileD.add(new Tile("plain",1,"town",3 ));
		tileD.add(new Tile("forest",2,"village",2 ));
						
		shuffle(tileD);
		//System.out.println(tileD.size()+"SIZZZZZZZZZZZZZZEEEEEEEEE dddddddd");
		_numCards+=5;
			
		//Create tile e and shuffle deck
		tileE.add(new Tile("plain",1,"castle",1 ));
		tileE.add(new Tile("plain",1,"town",3 ));
		tileE.add(new Tile("plain",1,"none",0 ));
		tileE.add(new Tile("forest",2,"castle",1 ));
		tileE.add(new Tile("forest",2,"village",2 ));			
			
		shuffle(tileE);
			
		_numCards+=5;
		//System.out.println(tileE.size()+"SIZZZZZZZZZZZZZZEEEEEEEEE eeeeeeeee");
		//set first hand with castle and removes it from deck A
		//_playerHand.add(new Tile("plain",1,"castle",1 ));
		/*for(int i=0;i<tileA.size();i++)
		{
			if(tileA.get(i).equals("plain","castle"))
			{
				tileA.remove(i);
				i=tileA.size();
			}
		}*/
		
		//set first hand with choice of 2nd card and removes it from deck A  
		for(int i=0;i<tileA.size();)
		{
			if(!tileA.get(i).equals(land,building)&&!tileA.get(i).equals("plain","castle"))
			{
				_playerHand.add(new Tile(tileA.get(i)));
				tileA.remove(i);
				//i=tileA.size();
			}
			else ++i;
		}
		
	
		_numCards-=2;
	}
	
	/**
	 * Get number of knights player has left
	 * 
	 * @param none
	 * @return int number of knights a player has left	 
	 */	
	public int getNumKnights()
	{
		return knights.size();	
	}
	
	/**
	 * Get number of cards in players hand
	 * 
	 * @param none
	 * @return int number of knights a player has left	 
	 */	
	public int getNumCardsInHand()
	{
		return _playerHand.size();
	}
	
	/**
	 * Removes knights from the players stack
	 * 
	 * @param iKnights amount of knights
	 * @return none
	 */
	public void removeNumKnights(int iKnights) {
		int count = 0;
		for (int i = 1; i < iKnights+1; i++) {
			knights.remove(count);
		}
	}
	
	/**
	 * Get the player number
	 * 
	 * @param none
	 * @return int number for the current Player object
	 */
	public int getPlayerNum(){
		return numPlayer;
	}
	
	/**
	 * Get number of cards player has left
	 * 
	 * @param none
	 * @return int number of cards current Player object has left	 
	 */	
	public int getNumCards()
	{		
		return _numCards;
	}
	
	/**
	 * Get color of player
	 * 
	 * @param none
	 * @return Color for current Player object	 
	 */	
	public Color getColor()
	{
		return _color;	
	}
	
	/**
	 * Get copy of Tile currently in hand
	 * 
	 * @param none
	 * @return list of tiles in players hand	 
	 */	
	public ArrayList<Tile> getAllTileInHand()
	{
		ArrayList<Tile> x=new ArrayList<Tile>();
		//ArrayList<Tile> old=getCurrentPlayer(j).getAllTileInHand();
		for(int i=0;i<_playerHand.size(); i++)
		{
			//String land, int knightsReq, String building, int points
			x.add(new Tile(_playerHand.get(i).getLandScape(),_playerHand.get(i).getQuantityKnights(), _playerHand.get(i).getBuildingStructure(), _playerHand.get(i).getWorth()));
		}
		return x;
	}
	
	/**
	 * Get string description of Tile in hand of Tile currently in hand
	 * 
	 * @param none
	 * @return list of Tile in players hand
	 * @return throw exception is player hand is larger than two	 
	 */	
	public String getDescriptionTilesInHand()
	{
		String land1="";
		String land2="";
		String building1="";
		String building2="";
		
		if(_playerHand.size()==2)
		{
			land1=_playerHand.get(0).getLandScape();
			land2=_playerHand.get(1).getLandScape();
			building1=_playerHand.get(0).getBuildingStructure();
			building2=_playerHand.get(1).getBuildingStructure();
			return "( "+land1+","+building1+" )"+"( "+land2+","+building2+" )";
		}
		else if(_playerHand.size()==1)
		{
			land1=_playerHand.get(0).getLandScape();			
			building1=_playerHand.get(0).getBuildingStructure();
			
			return "( "+land1+","+building1+" )"+"( no card )";
		}
		else if(_playerHand.size()==0)
		{
			return "no cards in hand";
		}
		return "( "+land1+","+building1+" )"+"( "+land2+","+building2+" )";	
	}
	
	/**
	 * Get tiles currently in hand based on specific card, removes from hand
	 * 
	 * @param String land type
	 * @param String building type
	 * @return the specified tile in players hand
	 * @return if doesn't exists throw IllegalArgumentException	 
	 * @return if doesn't exists or augments are null return null	 
	 */	
	public Tile removeTileInHand(String land,String building)
	{
		if(land==null||building==null)return null;
		Tile x=null;
		//for(Tiles x:_playerHand)
		for(int i=0;i<_playerHand.size();)
		{
			if(_playerHand.get(i).equals(land, building)) 
			{
				x=_playerHand.get(i);
				_playerHand.remove(i);
				_playerHand.add(getTopMostTile());
				--_numCards;
				return x;
			}
			else ++i;
		}
		//throw new IllegalArgumentException("No such tile in hand");
		return null;
	}

	// TODO remove debug statements...
	/**
	 * Get tiles currently in hand based on specific card, removes from hand
	 * 
	 * @param Tile a to be removed from hand
	 * @return none 
	 */	
	public void removeTileInHandTile(Tile a)
	{
		if(a.tland==null||a.tbuilding==null)throw new IllegalArgumentException("Tile has null arugument in removeTileInHandTile");
		Tile x=null;
		//for(Tiles x:_playerHand)
		int count=_numCards;
		for(int i=0;i<_playerHand.size();)
		{
			if(_playerHand.get(i).equals(a.tland, a.tbuilding)) 
			{
				x=_playerHand.get(i);
				_playerHand.remove(i);
				if(hasTileLeft())
				{
					_playerHand.add(getTopMostTile());
				}
				else
				{
					--_numCards;
				}
				i=_playerHand.size();
			}
			else ++i;
		}
		if(count==_numCards)throw new IllegalStateException("SHOTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT");
	}
	
	/**
	 * Get Tiles based on index, does not remove
	 * 	 
	 * @param int i for tile in hand to get
	 * @return Tile object returned 
	 */	
	public Tile getTileInHand(int i)
	{
		Tile x=null;		
		x=_playerHand.get(i);
		return x;		
	}
	
	// TODO remove this method if not beind used...
	/**
	 * Test method
	 * removes from hand first tile in hand
	 * @param string land and building type
	 * @return the specified tile in players hand
	 * @return if doesn't exists throw IllegalArgumentException	 
	 * @return if doesn't exists or augments are null return null	 
	 */	
	/*public Tile removeFirstTileInHandAndDraw()
	{
		
		Tile x=null;		
		
		x=_playerHand.get(0);
		_playerHand.remove(0);
		_playerHand.add(getTopMostTile());
		//--_numCards;
		return x;
			
	}*/
	
	// TODO remove debug statements...
	/**
	 * Get top-most tile
	 * 
	 * @param none
	 * @return Tile of the top- most tile	 
	 */	
	private Tile getTopMostTile()
	{
		if(_numCards==0)return null;

		if(tileA.size()!=0)
		{
			Tile a=new Tile(tileA.get(0));
			tileA.remove(0);
			--_numCards;
			//System.out.println("a");
			return a;
		}
		else if(tileB.size()!=0)
		{
			Tile a=new Tile(tileB.get(0));
			tileB.remove(0);
			--_numCards;
			//System.out.println("b");
			return a;
		}
		else if(tileC.size()!=0)
		{
			Tile a=new Tile(tileC.get(0));
			tileC.remove(0);
			--_numCards;
			//System.out.println("c");
			return a;
		}
		else if(tileD.size()!=0)
		{
			Tile a=new Tile(tileD.get(0));
			tileD.remove(0);
			--_numCards;
			//System.out.println("d");
			return a;
		}
		else if(tileE.size()!=0)
		{
			Tile a=new Tile(tileE.get(0));
			tileE.remove(0);
			--_numCards;
			//System.out.println("e");
			return a;
		}
		return null;
	}
	
	/**
	 * Get a usable knight
	 * 
	 * @param none
	 * @return return an unused knight	 
	 */	
	public Knight getKnights()
	{
		Knight a=new Knight(knights.get(0).getColor());
		knights.remove(0);		
		return a;
	}

	/**
	 * Return boolean if player has tiles
	 * 
	 * @param none
	 * @return if player has remaining tiles	 
	 */	
	public boolean hasTileLeft()
	{
		return !tileE.isEmpty();
	}
	
	/**
	 * shuffles deck
	 * 
	 * @param List of tiles
	 * @return void	 
	 */	
	public void shuffle(ArrayList<Tile> e)
	{
		for(int i=0;i<e.size();i++)
		{
			int r = i + (int) (Math.random() * (e.size()-i));
            Tile t = e.get(r); //gets randomly selected tile
            e.set(r,e.get(i)); //sets element at r index to element at i indes
            e.set(i,t); //sets element at i index to elment at r index
		}
	}
	
	/**
	 * Matches the color RGBY with correct icon for the player
	 * @param c color RGBY
	 * @author Andrew Landphier
	 */
	private void matchAndSetIcon(Color c){
		if ( c.equals(Color.BLUE)){
			setIconBlue();
		} else if (c.equals(Color.RED)){
			setIconRed();
		} else if (c.equals(Color.GREEN)){
			setIconGreen();
		} else if (c.equals(Color.YELLOW)){
			setIconYellow();
		}
	}
	
	

	/**
	 * Set the players icon
	 * @param i Icon image
	 * @author Andrew Landphier
	 */
	private void setIcon(ImageIcon i){
		icon = i;
	}	
	
	public ImageIcon getIcon(){
		return icon;
	}
	
	private void  setIconRed(){
		setIcon(new ImageIcon("ICONS.32X32/red.jpg"));
	}
	
	private void setIconBlue() {
		setIcon(new ImageIcon("ICONS.32X32/blue.jpg"));
	}
	
	private void setIconYellow(){
		setIcon(new ImageIcon("ICONS.32X32/yellow.jpg"));
	}
	
	private void setIconGreen(){
		setIcon(new ImageIcon("ICONS.32X32/green.jpg"));
	}
	
	
	
	
	
	
	
	
	
	
	
}
